package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;

	@Autowired
	private VodService vodService;

	@Autowired
	private AlbumInfoMapper albumInfoMapper;

	@Autowired
	private TrackStatMapper trackStatMapper;

	@Autowired
	private UserInfoFeignClient userInfoFeignClient;

	//保存声音
	@Override
	public void saveTrackInfo(TrackInfoVo trackInfoVo) {
		//1 添加声音基本信息 track_info
		TrackInfo trackInfo = new TrackInfo();
		BeanUtils.copyProperties(trackInfoVo, trackInfo);

		//需要手动设置
		//TODO 用户id
		trackInfo.setUserId(1L);

		//声音在专辑中的排序值
		//获取专辑下面最大order_num
		//select order_num
		// from track_info ti
		// where album_id=1
		// order by id desc
		// limit 1
		LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<TrackInfo>();
		//设置查询字段 order_num
		wrapper.select(TrackInfo::getOrderNum);
		//专辑id查询
		wrapper.eq(TrackInfo::getAlbumId, trackInfoVo.getAlbumId());
		//根据声音id降序
		wrapper.orderByDesc(TrackInfo::getId);
		//获取第一条记录
		wrapper.last(" limit 1 ");
		//调用
		TrackInfo trackInfo_ordernum = trackInfoMapper.selectOne(wrapper);

		int orderNum = 1;
		if(null != trackInfo_ordernum) {
			orderNum = trackInfo_ordernum.getOrderNum() + 1;
		}
		//最大值+1
		trackInfo.setOrderNum(orderNum);

		//声音其他信息，比如时长，大小，类型等
		//这些信息到腾讯云查询
		//根据声音的mediaFileId调用腾讯云方法获取
		TrackMediaInfoVo trackMediaInfoVo =
				vodService.getmediaInfoByFileId(trackInfoVo.getMediaFileId());
		//设置到trackInfo
		trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
		trackInfo.setMediaSize(trackMediaInfoVo.getSize());
		trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
		trackInfo.setMediaType(trackMediaInfoVo.getType());
		//调用方法添加
		trackInfoMapper.insert(trackInfo);

		//2 操作专辑表，修改专辑里面声音数量值，+1
		//根据专辑id查询专辑原始数据
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
		Integer includeTrackCount = albumInfo.getIncludeTrackCount();
		//把原始数量+1
		albumInfo.setIncludeTrackCount(includeTrackCount+1);
		//调用方法更新
		albumInfoMapper.updateById(albumInfo);

		//3 添加声音四个统计数据，初始值0 track_stat
		this.saveTrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_PLAY);
		this.saveTrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_COLLECT);
		this.saveTrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_PRAISE);
		this.saveTrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_COMMENT);
	}

	@Transactional
	@Override
	public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> pageParam, TrackInfoQuery trackInfoQuery) {
		return trackInfoMapper.selectUserTrackPage(pageParam,trackInfoQuery);
	}

	//删除
	@Override
	public void removeTrackInfo(Long trackId) {
		//根据声音id获取专辑id
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);

		//1 根据声音id删除声音基本信息
		trackInfoMapper.deleteById(trackId);

		//2 修改声音所在专辑声音数量-1
		Long albumId = trackInfo.getAlbumId();
		//根据专辑id查询专辑数据，把数量-1，进行更新
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		Integer includeTrackCount = albumInfo.getIncludeTrackCount();
		albumInfo.setIncludeTrackCount(includeTrackCount-1);
		albumInfoMapper.updateById(albumInfo);

		//3 删除声音统计数据
		LambdaQueryWrapper<TrackStat> wrapper = new LambdaQueryWrapper<TrackStat>();
		wrapper.eq(TrackStat::getTrackId, trackId);
		trackStatMapper.delete(wrapper);

		//4 删除腾讯云里面的声音文件
		//删除声音媒体
		vodService.removeTrack(trackInfo.getMediaFileId());
	}

	//修改声音
	@Override
	public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
		//1 根据trackId获取声音原始数据
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		//获取原始的音频文件id fileid
		String mediaFileId_database = trackInfo.getMediaFileId();
		//设置修改值
		BeanUtils.copyProperties(trackInfoVo, trackInfo);
		//判断声音文件是否修改
		//把前端传递过来的mediaFileId 和 数据库存储的mediaFileId进行比较
		if(!trackInfoVo.getMediaFileId().equals(mediaFileId_database)) {
			//重新调用腾讯云方法，根据新的mediaFileId查询音频文件最新信息
			TrackMediaInfoVo trackMediaInfoVo =
					vodService.getmediaInfoByFileId(trackInfoVo.getMediaFileId());
			if (null==trackMediaInfoVo){
				//	抛出异常
				throw new GuiguException(ResultCodeEnum.VOD_FILE_ID_ERROR);
			}
			//最新获取音频信息设置到trackInfo
			trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
			trackInfo.setMediaType(trackMediaInfoVo.getType());
			trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
			trackInfo.setMediaSize(trackMediaInfoVo.getSize());

			//删除之前声音文件
			vodService.removeTrack(mediaFileId_database);
		}

		//调用方法修改
		trackInfoMapper.updateById(trackInfo);
	}

	//根据专辑id查询专辑声音数据
	@Override
	public IPage<AlbumTrackListVo>
	                 findAlbumTrackPage(Page<AlbumTrackListVo> pageParam,
													  Long albumId, Long userId) {
		//根据专辑id分页查询得到数据
		IPage<AlbumTrackListVo> pageInfo =
				 trackInfoMapper.findAlbumTrackPage(pageParam,albumId);
		List<AlbumTrackListVo> albumTrackListVos = pageInfo.getRecords();

		//根据专辑id获取专辑信息
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		Assert.notNull(albumInfo,"专辑数据为空");
		////付费类型: 0101-免费、0102-vip免费、0103-付费
		String payType = albumInfo.getPayType();

		//1 根据userId判断当前是否登录
		//1.1 如果userId==null，当前没有进行登录
		if(userId == null) {
			// 如果专辑免费直接观看
			// 如果专辑不是免费的，根据tracks_for_free去掉试听集数，其他的是收费的
			//付费类型: 0101-免费、0102-vip免费、0103-付费
			if(!"0101".equals(payType)) {
				//获取专辑所有声音集合
				List<AlbumTrackListVo> allAlbumTrackList = pageInfo.getRecords();
				//获取专辑试听集数
				Integer tracksForFree = albumInfo.getTracksForFree();
				//从所有声音集合过滤掉试听集数,声音表有order_num排序 order_num>试听集数
				List<AlbumTrackListVo> trackListVoList =
						allAlbumTrackList.stream().filter(albumTrackListVo ->
								albumTrackListVo.getOrderNum().intValue()>tracksForFree)
								.collect(Collectors.toList());
				//trackListVoList集合每个对象中 isShowPaidMark = true
				if(!CollectionUtils.isEmpty(trackListVoList)) {
					trackListVoList.forEach(albumTrackListVo -> {
						//	显示付费通知
						// isShowPaidMark=flase免费的  isShowPaidMark=true收费的
						albumTrackListVo.setIsShowPaidMark(true);
					});
				}
			}
		} else {  //1.2 如果登录状态
			boolean isNeedPaid = false;

			//付费类型: 0101-免费、0102-vip免费、0103-付费
			//判断如果专辑vip免费的
			if("0102".equals(payType)) {
				// 根据当前登录的用户id获取用户信息，判断用户是否开通vip
				// 如果用户没有开通vip，     收费
				Result<UserInfoVo> userInfoVoResult =
						userInfoFeignClient.getUserInfoVo(userId);
				UserInfoVo userInfoVo = userInfoVoResult.getData();
				Assert.notNull(userInfoVo,"用户信息为空");
				Integer isVip = userInfoVo.getIsVip();
				if (isVip.intValue() == 0){
					isNeedPaid = true;
				}

				//* 如果用户开通VIP但是过期了，收费
				Date vipExpireTime = userInfoVo.getVipExpireTime();
				if(isVip.intValue() == 1 && vipExpireTime.before(new Date())) {
					isNeedPaid = true;
				}
			} else if("0103".equals(payType)){ //0103-付费
				isNeedPaid = true;
			}

			//判断如果专辑付费 收费
			if(isNeedPaid) {
				//* 判断当前用户是否购买专辑，购买过，免费
				// 如果用户购买整个专辑，专辑里面所有声音免费
				// 如果用户只是购买了专辑某些声音，购买的声音免费的，其他收费
				//获取排除试听声音列表
				List<AlbumTrackListVo> albumTrackNeedPaidListVoList =
						pageInfo.getRecords().stream()
								.filter(albumTrackListVo ->
										albumTrackListVo.getOrderNum().intValue() > albumInfo.getTracksForFree())
								.collect(Collectors.toList());

				if(!CollectionUtils.isEmpty(albumTrackNeedPaidListVoList)) {
					//albumTrackNeedPaidListVoList获取所有声音id
					List<Long> trackIdList =
							albumTrackNeedPaidListVoList.stream()
									.map(AlbumTrackListVo::getTrackId).collect(Collectors.toList());

					//远程调用接口，查询用户购买过的专辑或者声音
					//[1,2,3,4]
					Result<Map<Long, Integer>> mapResult =
							userInfoFeignClient
									.userIsPaidTrack(albumId,trackIdList);
					//map的key是声音id  value：1购买过  0没有购买过
					Map<Long, Integer> map = mapResult.getData();
					Assert.notNull(map,"为空");
					//albumTrackNeedPaidListVoList集合，声音id比较，1：isShowPaidMark = false
					albumTrackNeedPaidListVoList.forEach(albumTrackListVo -> {
						Long trackId = albumTrackListVo.getTrackId();

						/*Integer mark = map.get(trackId);
						if(mark == 1) {//购买过
							albumTrackListVo.setIsShowPaidMark(false);
						} else if(mark==0) { //没有买过
							albumTrackListVo.setIsShowPaidMark(true);
						}*/

						boolean isMark = map.get(trackId)==1?false:true;
						albumTrackListVo.setIsShowPaidMark(isMark);
					});
				}
			}
		}
		return pageInfo;
	}

	//更新声音播放量
	@Override
	public void updateStat(TrackStatMqVo trackStatMqVo) {
		Long trackId = trackStatMqVo.getTrackId();
		Integer count = trackStatMqVo.getCount();
		String statType = trackStatMqVo.getStatType();

		//根据声音id+ 0701获取数据
		LambdaQueryWrapper<TrackStat> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(TrackStat::getTrackId, trackId);
		wrapper.eq(TrackStat::getStatType, statType);
		TrackStat trackStat = trackStatMapper.selectOne(wrapper);

		//设置修改值
		trackStat.setStatNum(trackStat.getStatNum()+count);

		//调用方法更新
		trackStatMapper.updateById(trackStat);
	}

	//显示可以购买声音集数
	@Override
	public List<Map<String, Object>> findUserTrackPaidList(Long trackId) {
		//1 根据声音id获取声音对象（本集）
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		//2 根据声音里面的专辑id获取专辑对象
		AlbumInfo albumInfo =
				albumInfoMapper.selectById(trackInfo.getAlbumId());

		//3 远程调用：根据专辑id + 用户id 查询用户在这个购买过哪些声音
		//返回用户在专辑里面购买过声音id列表
		Result<List<Long>> isPaidResult =
				  userInfoFeignClient.findUserIsPaidTrack(trackInfo.getAlbumId());
		List<Long> paidTrackIdList = isPaidResult.getData();

		//4 获取当前可以购买所有声音，本集后面所有声音
		//根据专辑id 查询专辑里面所有声音，条件：大于本集ordernum
		LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(TrackInfo::getAlbumId,trackInfo.getAlbumId());
		wrapper.gt(TrackInfo::getOrderNum, trackInfo.getOrderNum());
		List<TrackInfo> trackInfoList = trackInfoMapper.selectList(wrapper);

		//从可以购买所有声音集合获取所有声音id
		List<Long> idAllList =
				trackInfoList.stream().map(TrackInfo::getId)
						    .collect(Collectors.toList());

		//5 把可以购买所有声音中，去掉购买过的声音
		// idAllList去掉购买id  购买id集合paidTrackIdList
		//  (1 2 3 4 5)   +   (3 4)   =  1 2 5
		//创建list集合，封装没有购买过声音列表
		List<Long> trackIdNoReaptList = new ArrayList<>();
		if(CollectionUtils.isEmpty(paidTrackIdList)) { //用户没有购买过
			trackIdNoReaptList = idAllList;
		} else { ////用户购买过
			trackIdNoReaptList =
					idAllList.stream()
							.filter(id -> !paidTrackIdList.contains(id))
							.collect(Collectors.toList());
		}

		//6 构建显示内容，每部分显示map集合，显示多个，list集合
		List<Map<String, Object>> list = new ArrayList<>();
		//本集
		if(trackIdNoReaptList.size() >=0) {
			Map<String, Object> map = new HashMap<>();
			map.put("name","本集");
			map.put("price",albumInfo.getPrice());
			map.put("trackCount", 0);
			list.add(map);
		}
		// 大于0 小于等于10
		if(trackIdNoReaptList.size() > 0 && trackIdNoReaptList.size() <= 10) {
			Map<String, Object> map = new HashMap<>();
			map.put("name","后"+trackIdNoReaptList.size()+"集");
			//计算价格
			BigDecimal price =
					albumInfo.getPrice()
							.multiply(new BigDecimal(trackIdNoReaptList.size()));
			map.put("price",price);
			map.put("trackCount", trackIdNoReaptList.size());
			list.add(map);
		}
		// 19
		if(trackIdNoReaptList.size() > 10) {
			Map<String, Object> map = new HashMap<>();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(10));
			map.put("name", "后10集");
			map.put("price", price);
			map.put("trackCount", 10);
			list.add(map);
		}
		// 后20集
		if(trackIdNoReaptList.size() > 10 && trackIdNoReaptList.size() <= 20) {
			Map<String, Object> map = new HashMap<>();
			int count = trackIdNoReaptList.size();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(count));
			map.put("name", "后"+count+"集");
			map.put("price", price);
			map.put("trackCount", count);
			list.add(map);
		}
		if(trackIdNoReaptList.size() > 20) {
			Map<String, Object> map = new HashMap<>();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(20));
			map.put("name", "后20集");
			map.put("price", price);
			map.put("trackCount", 20);
			list.add(map);
		}

		//后30集
		if(trackIdNoReaptList.size() > 20 && trackIdNoReaptList.size() <= 30) {
			Map<String, Object> map = new HashMap<>();
			int count = trackIdNoReaptList.size();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(count));
			map.put("name", "后"+count+"集");
			map.put("price", price);
			map.put("trackCount", count);
			list.add(map);
		}
		if(trackIdNoReaptList.size() > 30) {
			Map<String, Object> map = new HashMap<>();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(30));
			map.put("name", "后30集");
			map.put("price", price);
			map.put("trackCount", 30);
			list.add(map);
		}

		//后50集
		if(trackIdNoReaptList.size() > 30 && trackIdNoReaptList.size() <= 50) {
			Map<String, Object> map = new HashMap<>();
			int count = trackIdNoReaptList.size();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(count));
			map.put("name", "后"+count+"集");
			map.put("price", price);
			map.put("trackCount", count);
			list.add(map);
		}
		// 最多购买50集;
		if(trackIdNoReaptList.size() > 50) {
			Map<String, Object> map = new HashMap<>();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(50));
			map.put("name", "后50集");
			map.put("price", price);
			map.put("trackCount", 50);
			list.add(map);
		}

		return list;
	}

	//根据本集声音id + 购买集数，获取声音列表
	@Override
	public List<TrackInfo> findPaidTrackInfoList(Long trackId,
												 Integer trackCount) {
		//1 获取本集声音id获取声音数据
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);

		//2 根据本集声音所属专辑id + 用户id 查询用户购买这个专辑声音id列表
		Result<List<Long>> userIsPaidTrackResult =
				userInfoFeignClient.findUserIsPaidTrack(trackInfo.getAlbumId());
		List<Long> paidTrackIdList = userIsPaidTrackResult.getData();

		//3 查询声音列表
		// 声明一个声音对象集合
		List<TrackInfo> trackInfoList = new ArrayList<>();
		//3.1 trackCount>0 购买本集后多少集数据
		if(trackCount > 0) {
			LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
			// 本集声音所属的专辑id
			wrapper.eq(TrackInfo::getAlbumId,trackInfo.getAlbumId());

			// 大于本集声音ordernum
			wrapper.gt(TrackInfo::getOrderNum,trackInfo.getOrderNum());

			// ordernum排序
			wrapper.orderByAsc(TrackInfo::getOrderNum);

			// 排除掉购买过声音
			if (!CollectionUtils.isEmpty(paidTrackIdList)){
				wrapper.notIn(TrackInfo::getId,paidTrackIdList);
			}

			// 限制查询多少集声音
			wrapper.last(" limit "+trackCount);

			//调用方法
			trackInfoList = trackInfoMapper.selectList(wrapper);
		} else {
			//3.2 trackCount==0 购买本集
			trackInfoList.add(trackInfo);
		}
		//返回集合
		return trackInfoList;
	}

	/**
	 * 初始化统计数量
	 * @param trackId
	 * @param trackType
	 */
	private void saveTrackStat(Long trackId, String trackType) {
		TrackStat trackStat = new TrackStat();
		trackStat.setTrackId(trackId);
		trackStat.setStatType(trackType);
		trackStat.setStatNum(0);
		this.trackStatMapper.insert(trackStat);
	}

}
